import logging
from abc import ABC, abstractmethod
from typing import List
import pydantic
import sqlalchemy as sa
from fastapi import Request
from fastapi_pagination.ext.databases import paginate

from admin.schemas.system_user import UserListIn, UserAddIn, UserEditIn, UserOut
from admin.service.base_service import BaseService
from schema_base import PageInationResult
from utils.db_operate import generate_query_conditions

from models import system_user

logger = logging.getLogger(__name__)


class IUserService(ABC):
    @abstractmethod
    async def list(self, list_in: UserListIn) -> PageInationResult[UserOut]:
        pass

    @abstractmethod
    async def detail(self, id_: int) -> UserOut:
        pass

    @abstractmethod
    async def add(self, add_in: UserAddIn):
        pass

    @abstractmethod
    async def edit(self, edit_in: UserEditIn):
        pass

    @abstractmethod
    async def delete(self, id_: int):
        pass

    @abstractmethod
    async def all(self, list_in: UserListIn) -> List[UserOut]:
        pass


class UserService(IUserService,BaseService):
    # expecting a Table object named users exported from meeting_backend.models
    tableModel = system_user.SystemUser.__table__  # set below to actual table

    def __init__(self, request: Request):
        super().__init__(request)

    @classmethod
    async def instance(cls, request: Request):
        return cls(request)

    async def list(self, list_in: UserListIn) -> PageInationResult[UserOut]:
        columns = [self.tableModel]
        where = generate_query_conditions(list_in, self.tableModel)
        query = sa.select(*columns).where(*where).select_from(self.tableModel).order_by(self.tableModel.c.id.desc())
        res = await paginate(self.conn, query)
        return res

    async def detail(self, id_: int) -> UserOut:
        model = await self.conn.fetch_one(self.tableModel.select().where(self.tableModel.c.id == id_).limit(1))
        assert model, "用户不存在"
        return UserOut.from_orm(model)

    async def add(self, add_in: UserAddIn):
        values = add_in.dict(exclude_none=True)
        await self.conn.execute(self.tableModel.insert().values(values))

    async def edit(self, edit_in: UserEditIn):
        model = await self.conn.fetch_one(self.tableModel.select().where(self.tableModel.c.id == edit_in.id).limit(1))
        assert model, "用户不存在"
        values = edit_in.dict(exclude_none=True)
        values.pop("id", None)
        await self.conn.execute(self.tableModel.update().where(self.tableModel.c.id == edit_in.id).values(values))

    async def delete(self, id_: int):
        model = await self.conn.fetch_one(self.tableModel.select().where(self.tableModel.c.id == id_).limit(1))
        assert model, "用户不存在"
        await self.conn.execute(self.tableModel.delete().where(self.tableModel.c.id == id_))

    async def all(self, list_in: UserListIn) -> List[UserOut]:
        where = generate_query_conditions(list_in, self.tableModel)
        q = sa.select(self.tableModel).where(*where).select_from(self.tableModel).order_by(self.tableModel.c.id)
        all_datas = await self.conn.fetch_all(q)
        return pydantic.parse_obj_as(List[UserOut], all_datas)
